package com.frame.common.db;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.dao.DataAccessException;

import com.frame.common.context.SpringContainer;
import com.frame.common.util.ClassUtils;

public abstract class MyBatisModel<T,E extends BaseMapper<T>> extends PageInfo {

	private static final long serialVersionUID = -926701373773116224L;

	public static final String CENTERDB_SQLMAPCLIENT_ID = "sqlMapClient";

	//public static final String HOTSHOP_SQLMAPCLIENT_ID = "hotshopBaseSqlMapClient";

	private static final String DEFAULT_STATEMENT_SAVE = "save";
	private static final String DEFAULT_STATEMENT_LIST = "find";
	private static final String DEFAULT_STATEMENT_GET = "load";
	private static final String DEFAULT_STATEMENT_DELETE = "delete";
	private static final String DEFAULT_STATEMENT_UPDATE = "update";
	private static final String DEFAULT_STATEMENT_COUNT = "count";
	private static final String DEFAULT_FROEIGN_FIELD_NAME = "Id";
	private static final String DEFAULT_PK_NAME = "id";
	
	private Class<E> mapperClass;

	private static int IS_READ = 1;
	
	private static int IS_WRITE = 2;
	
	protected String pk = DEFAULT_PK_NAME;

	protected String ibatisClientId = CENTERDB_SQLMAPCLIENT_ID;

	protected int id;

	protected String startTime;

	protected String endTime;

	private String tableKey; // 分表字段

	private int table; // 表号

	private Map<String, MyBatisModel<?,?>> foreignKeys;

	private int tableNum; // 分表数量

	public String toStringFun;
	
	public SqlSessionDaoSupport sqlMapClient;
	
	private static String [] READ_STR = {"",""};
	

	/**
	 * 设置表的主键,加入到model的构造方法里面,如果主键是"id",无需调用
	 * @param field 主键字段名
	 */
	protected void setPk(String field) {
		this.pk = field;
	}

	/**
	 * 设置分表accountId字段 ,加入到model的构造方法里面,可以根据字段设置表名
	 * @param tableKey 分表字段
	 * @param tableNum 分表的数量
	 */
	protected void setTableKey(String tableKey, int tableNum) {
		this.tableKey = tableKey;
		this.tableNum = tableNum;
	}

	/**
	 * 设置数据源
	 * @param ibatisClientId
	 * ibatis文件配置,默认值:optSqlMapClient
	 */
	public void setIbatisClientId(String ibatisClientId) {
		this.ibatisClientId = ibatisClientId;
	}
	
	public void setMapperClass(Class<E> mapperClass) throws DataAccessException {
		this.mapperClass = mapperClass;
	}

	/**
	 * 设置数据操作对象  读写分离,要有多个数据源
	 * @param readOrWrite:1:读，2:写
	 */
	public void setIBatisClient(int readOrWrite) {
		if (this.getSqlMapClient() == null){
			String ibatisClient = ibatisClientId;
			if(readOrWrite == IS_READ){
				ibatisClient = ibatisClientId + getReadStr();
			}else{ 
				ibatisClient = ibatisClientId;
			}
			//获得Mybatis的sessionFactory
		    sqlMapClient = (SqlSessionDaoSupport)SpringContainer.getBean(ibatisClient);
		}
	}
	
	private String getReadStr(){
		return READ_STR[new Random().nextInt(2)];
	}
	
	private SqlSessionDaoSupport getSqlMapClient() {
		return sqlMapClient;
	}

	/**
	 * 获取单个对象
	 * 
	 * @return MyBatisModel对象
	 */
	public T load() {
		return (T)this.load(DEFAULT_STATEMENT_GET);
	}
	
	public E fetchMapperClass() throws DataAccessException {
		this.setIBatisClient(IS_READ);
		return sqlMapClient.getSqlSession()
		.getConfiguration().getMapper(mapperClass, sqlMapClient.getSqlSession());
	}
	
	/**
	 * 获取单个对象
	 * @param statementName ibatis文件中statement名称
	 * @return MyBatisModel对象
	 */
	public T load(String statementName) {
		this.setIBatisClient(IS_READ);
		//this.setTableFromTableKey();
		BaseMapper<T> baseMapper = (BaseMapper<T>)sqlMapClient.getSqlSession()
		.getConfiguration().getMapper(mapperClass, sqlMapClient.getSqlSession());
		T model = baseMapper.load(this);
		if (model != null && this.foreignKeys != null) {
			for (String field : this.foreignKeys.keySet()) {
				// logger.debug("Foreign key field is :" + field);
				MyBatisModel<?,?> foreignModel = this.foreignKeys.get(field);
				try {
					String key = BeanUtils.getProperty(model, field);
					// logger.debug("Foreign key's " + field + " value is:" +key);
					if (Integer.valueOf(key) > 0){
						foreignModel.setPK(Integer.valueOf(key));
					}else{
						continue;
					}
					//把返回的外键包装
					BeanUtils.setProperty(model, ClassUtils.getLowerCaseModelName(foreignModel), foreignModel.load());
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				} catch (NoSuchMethodException e) {
					e.printStackTrace();
				}
			}
		}
		return model;
	}
	
	//给外键对像生成一个自定义的PK的属性
	private void setPK(int pk) {
		if (this.pk.equals(DEFAULT_PK_NAME)) {
			this.setId(pk);
		} else {
			try {
				BeanUtils.setProperty(this, this.pk, Integer.valueOf(pk));
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}	
	
	public void setId(int id) {
	    this.id = id;
    }
	
	/**
	 * 关联查询
	 * 
	 * @param field
	 *            关联的字段
	 * @param modelClass
	 *            关联的类
	 * @return IBatisModel对象
	 */
	public MyBatisModel<?,?> foreignKey(String field,String pk, Class<? extends MyBatisModel<?,?>> modelClass) {
		if (field == null || StringUtils.isEmpty(field)){
			return this;
		}
		if (this.foreignKeys == null){
			this.foreignKeys = new HashMap<String, MyBatisModel<?,?>>();
		}
		try {
			MyBatisModel<?,?> foreignMode = modelClass.newInstance();
			foreignMode.setPk(pk);
			this.foreignKeys.put(field,foreignMode);
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return this;
	}

	public MyBatisModel<?,?> foreignKey(String field,Class<? extends MyBatisModel<?,?>> modelClass) {
		return foreignKey(field,DEFAULT_PK_NAME,modelClass);
	}
	/**
	 * 查询是否存在
	 * 
	 * @return
	 */
//	public boolean exist() {
//		return exist(DEFAULT_STATEMENT_COUNT);
//	}

	/**
	 * 查询是否存在
	 * 
	 * @param statementName
	 * @return
	 */
//	public boolean exist(String statementName) {
//		this.setIBatisClient(IS_READ);
//		//this.setTableFromTableKey();
//		Integer num = (Integer) this.getSqlMapClientTemplate().queryForObject(ClassUtils.getLowerCaseModelName(this) + "." + statementName, this);
//		if (num == null || num == 0)
//			return false;
//		return true;
//	}
//
	/**
	 * 查询int 类型值
	 * 
	 * @return int
	 */
	public int fetchInt() {
		return this.getInt(DEFAULT_STATEMENT_COUNT);
	}

	/**
	 * 查询int 类型值
	 * 
	 * @return int
	 */
	public int getInt(String statementName) {
		System.out.println(IS_READ);
		this.setIBatisClient(IS_READ);
		//this.setTableFromTableKey();
		BaseMapper<T> baseMapper = (BaseMapper<T>)sqlMapClient.getSqlSession()
		.getConfiguration().getMapper(mapperClass, sqlMapClient.getSqlSession());
		return baseMapper.getInt(this);
	}
//
//	/**
//	 * 查询string 类型值
//	 * 
//	 * @return int
//	 */
//	public String getString() {
//		return this.getString(DEFAULT_STATEMENT_COUNT);
//	}
//
//	/**
//	 * 查询string 类型值
//	 * 
//	 * @return int
//	 */
//	public String getString(String statementName) {
//		this.setIBatisClient(IS_READ);
//		this.setTableFromTableKey();
//		return (String) this.getSqlMapClientTemplate().queryForObject(ClassUtils.getLowerCaseModelName(this) + "." + statementName, this);
//	}
//
	/**
	 * 查询列表
	 * 
	 * @return MyBatisModel对象的列表
	 */
	public List<T> find() {
		return (List<T>) this.find(DEFAULT_STATEMENT_LIST);
	}
//
//	public List<T> findList(String pkname) {
//		return (List<T>) this.find(DEFAULT_STATEMENT_LIST, pkname);
//	}
//
	/**
	 * 查询列表
	 * 
	 * @param statementName
	 *            ibatis文件中statement名称
	 * @return MyBatisModel对象
	 */
	public List<T> find(String statementName) {
		this.setIBatisClient(IS_READ);
		//this.setTableFromTableKey();
		BaseMapper<T> baseMapper = (BaseMapper<T>)sqlMapClient.getSqlSession()
		.getConfiguration().getMapper(mapperClass, sqlMapClient.getSqlSession());
		if (this.getPerPageSize() > 0 && !this.isLimit()) {
			this.setDataCount(baseMapper.getInt());
			this.calculate();
			//如果数据库中没有记录就返回空列表
			if (this.getDataCount() == 0) {
				return new ArrayList<T>();
			}
		}
		List<T> list = baseMapper.find(this);

		if (this.foreignKeys != null) {
			for (T m : list) {
				Set<String> keySet = this.foreignKeys.keySet();
				for (String field : keySet) {
					MyBatisModel<?,?> model = this.foreignKeys.get(field);
					try {
						String key = BeanUtils.getProperty(m, field);

						if (Integer.valueOf(key) > 0)
							model.setPK(Integer.valueOf(key));
						else
							continue;

						BeanUtils.setProperty(m, ClassUtils.getLowerCaseModelName(model), model.load());
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					} catch (NoSuchMethodException e) {
						e.printStackTrace();
					}
				}
			}
		}
		return list;
	}
//
//	/**
//	 * 该方法可以加载一个一对多的关系模型
//	 * 
//	 * @param statementName
//	 * @param pkname
//	 * @return
//	 */
//	@SuppressWarnings("unchecked")
//	public List<T> find(String statementName, String pkname) {
//		this.setIBatisClient(IS_READ);
//		this.setTableFromTableKey();
//		if (this.getPerPageSize() > 0) {
//			this.setDataCount((Integer) this.getSqlMapClientTemplate().queryForObject(
//					ClassUtils.getLowerCaseModelName(this) + "."
//							+ (statementName == DEFAULT_STATEMENT_LIST ? DEFAULT_STATEMENT_COUNT : statementName + "Count"), this));
//			this.calculate();
//
//			if (this.getDataCount() == 0) {
//				return new ArrayList<T>();
//			}
//		}
//
//		List<T> list = this.getSqlMapClientTemplate().queryForList(ClassUtils.getLowerCaseModelName(this) + "." + statementName, this);
//
//		if (this.foreignKeys != null) {
//			for (T m : list) {
//				Set<String> keySet = this.foreignKeys.keySet();
//				for (String field : keySet) {
//					MyBatisModel model = this.foreignKeys.get(field);
//					try {
//						String key = BeanUtils.getProperty(m, field);
//						model.setPKName(pkname);
//						model.setPK(Integer.valueOf(key));
//						BeanUtils.setProperty(m, ClassUtils.getLowerCaseModelName(model), model.find());
//					} catch (IllegalAccessException e) {
//						e.printStackTrace();
//					} catch (InvocationTargetException e) {
//						e.printStackTrace();
//					} catch (NoSuchMethodException e) {
//						e.printStackTrace();
//					}
//				}
//			}
//		}
//		return list;
//	}
//
	/**
	 * 插入数据对象
	 * 
	 * @return 插入后的主键
	 * @throws Exception
	 */
	public Object save() throws Exception {
		return this.save(DEFAULT_STATEMENT_SAVE);
	}

	/**
	 * 插入数据对象
	 * 
	 * @param statementName ibatis文件中statement名称
	 * @return 插入后的主键
	 * @throws Exception
	 */
	public Object save(String statementName) throws Exception {
		this.setIBatisClient(IS_WRITE);
		BaseMapper<T> baseMapper = (BaseMapper<T>)sqlMapClient.getSqlSession()
		.getConfiguration().getMapper(mapperClass, sqlMapClient.getSqlSession());
		//setTableFromTableKey();
		return baseMapper.save(this);
	}
//
//	/**
//	 * 修改数据
//	 * 
//	 * @return 修改的数据条数
//	 * @throws Exception
//	 */
//	public int update() throws Exception {
//		return this.update(DEFAULT_STATEMENT_UPDATE);
//	}
//
//	/**
//	 * 修改数据
//	 * 
//	 * @param statementName
//	 *            ibatis文件中statement名称
//	 * @return 修改的数据条数
//	 * @throws Exception
//	 */
//	public int update(String statementName) throws Exception {
//		this.setIBatisClient(IS_WRITE);
//		setTableFromTableKey();
//		int n = this.getSqlMapClientTemplate().update(ClassUtils.getLowerCaseModelName(this) + "." + statementName, this);
//		return n;
//	}
//
//	/**
//	 * 修改一条记录,如果不存在就创建
//	 * 
//	 * @return 创建返回true,修改返回false;
//	 * @throws Exception
//	 */
//	public boolean saveOrUpdate() throws Exception {
//		this.setIBatisClient(IS_WRITE);
//		setTableFromTableKey();
//		return this.saveOrUpdate(DEFAULT_STATEMENT_SAVE, DEFAULT_STATEMENT_UPDATE);
//	}
//
//	/**
//	 * 修改一条记录,如果不存在就创建
//	 * 
//	 * @param saveStatementName
//	 * @param updateStatementName
//	 * @return 创建返回true,修改返回false;
//	 * @throws Exception
//	 */
//	public boolean saveOrUpdate(String saveStatementName, String updateStatementName) throws Exception {
//		this.setIBatisClient(IS_WRITE);
//		setTableFromTableKey();
//		if (this.update(updateStatementName) == 0) {
//			try {
//				this.save(saveStatementName);
//				return true;
//			} catch (Exception e) {
//				this.update(updateStatementName);
//			}
//		}
//		return false;
//	}
//
//	/**
//	 * 删除数据
//	 * 
//	 * @return 删除的数据条数
//	 * @throws Exception
//	 */
//	public int delete() throws Exception {
//		return this.delete(DEFAULT_STATEMENT_DELETE);
//	}
//
//	/**
//	 * 删除数据
//	 * 
//	 * @param statementName
//	 *            ibatis文件中statement名称
//	 * @return 删除的数据条数
//	 * @throws Exception
//	 */
//	public int delete(String statementName) throws Exception {
//		this.setIBatisClient(IS_WRITE);
//		setTableFromTableKey();
//		return this.getSqlMapClientTemplate().delete(ClassUtils.getLowerCaseModelName(this) + "." + statementName, this);
//	}
//
//	/**
//	 * 批量修改数据
//	 * 
//	 * @param list
//	 *            要修改的列表
//	 */
//	public void updateList(final List<MyBatisModel<T>> list) {
//		this.updateList(list, DEFAULT_STATEMENT_UPDATE);
//	}
//
//	/**
//	 * 批量修改数据
//	 * 
//	 * @param list
//	 *            要修改的列表
//	 * @param statementName
//	 *            ibatis文件中statement名称
//	 */
//	public void updateList(final List<MyBatisModel<T>> list, final String statementName) {
//		this.setIBatisClient(IS_WRITE);
//		this.getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
//			public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
//				executor.startBatch();
//				for (MyBatisModel<T> obj : list) {
//					obj.setTableFromTableKey();
//					executor.update(ClassUtils.getLowerCaseModelName(obj) + "." + statementName, obj);
//				}
//				return executor.executeBatch();
//			}
//		});
//	}
//
//	/**
//	 * 批量插入数据
//	 * 
//	 * @param list
//	 *            要插入的列表
//	 */
//	public void saveList(final List<MyBatisModel<T>> list) {
//		this.saveList(list, DEFAULT_STATEMENT_SAVE);
//	}
//
//	/**
//	 * 批量插入数据
//	 * 
//	 * @param list
//	 *            要插入的列表
//	 * @param statementName
//	 *            ibatis文件中statement名称
//	 */
//	public void saveList(final List<MyBatisModel<T>> list, final String statementName) {
//		this.setIBatisClient(IS_WRITE);
//		this.getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
//			public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
//				executor.startBatch();
//				for (MyBatisModel<T> obj : list) {
//					obj.setTableFromTableKey();
//					executor.insert(ClassUtils.getLowerCaseModelName(obj) + "." + statementName, obj);
//				}
//				return executor.executeBatch();
//			}
//		});
//	}
//
//	/**
//	 * 批量删除数据
//	 * 
//	 * @param list
//	 *            要修改的列表
//	 */
//	public void deleteList(final List<MyBatisModel<T>> list) {
//		this.deleteList(list, DEFAULT_STATEMENT_DELETE);
//	}
//
//	/**
//	 * 批量删除数据
//	 * 
//	 * @param list
//	 *            要修改的列表
//	 * @param statementName
//	 *            ibatis文件中statement名称
//	 */
//	public void deleteList(final List<MyBatisModel<T>> list, final String statementName) {
//		this.setIBatisClient(IS_WRITE);
//		this.getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
//			public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
//				executor.startBatch();
//				for (MyBatisModel<T> obj : list) {
//					obj.setTableFromTableKey();
//					executor.delete(ClassUtils.getLowerCaseModelName(obj) + "." + statementName, obj);
//				}
//				return executor.executeBatch();
//			}
//		});
//	}
//
//	/**
//	 * 设置每页数据量
//	 * 
//	 * @param num
//	 *            每页数据量
//	 * @return MyBatisModel对象
//	 */
//	public MyBatisModel setPageNum(int num) {
//		this.setPerPageSize(num);
//		return this;
//	}
//
//	/**
//	 * 对字段添加%%
//	 * 
//	 * @param field
//	 *            字段名
//	 * @return MyBatisModel对象
//	 */
//	public MyBatisModel like(String field) {
//		if (StringUtils.isEmpty(field))
//			return this;
//
//		try {
//			String value = BeanUtils.getProperty(this, field);
//			if (!StringUtils.isEmpty(value))
//				BeanUtils.setProperty(this, field, "%" + value + "%");
//		} catch (IllegalAccessException e) {
//			e.printStackTrace();
//		} catch (InvocationTargetException e) {
//			e.printStackTrace();
//		} catch (NoSuchMethodException e) {
//			e.printStackTrace();
//		}
//		return this;
//	}
//
//	/**
//	 * 设置字段以什么开头
//	 * 
//	 * @param field
//	 *            字段名
//	 * @return MyBatisModel对象
//	 */
//	public MyBatisModel startsWith(String field) {
//		if (StringUtils.isEmpty(field))
//			return this;
//		try {
//			String value = BeanUtils.getProperty(this, field);
//			if (!StringUtils.isEmpty(value))
//				BeanUtils.setProperty(this, field, value + "%");
//		} catch (IllegalAccessException e) {
//			e.printStackTrace();
//		} catch (InvocationTargetException e) {
//			e.printStackTrace();
//		} catch (NoSuchMethodException e) {
//			e.printStackTrace();
//		}
//		return this;
//	}
//
//	/**
//	 * 设置字段以什么结尾
//	 * 
//	 * @param field
//	 *            字段名
//	 * @return MyBatisModel对象
//	 */
//	public MyBatisModel endsWith(String field) {
//		if (StringUtils.isEmpty(field))
//			return this;
//		try {
//			String value = BeanUtils.getProperty(this, field);
//			if (!StringUtils.isEmpty(value))
//				BeanUtils.setProperty(this, field, "%" + value);
//		} catch (IllegalAccessException e) {
//			e.printStackTrace();
//		} catch (InvocationTargetException e) {
//			e.printStackTrace();
//		} catch (NoSuchMethodException e) {
//			e.printStackTrace();
//		}
//		return this;
//	}
//
//	/**
//	 * 关联查询
//	 * 
//	 * @param modelClass
//	 *            关联的类
//	 * @return MyBatisModel对象
//	 */
//	public MyBatisModel foreignKey(Class<? extends MyBatisModel> modelClass) {
//		return this.foreignKey(ClassUtils.getLowerCaseClassName(modelClass) + DEFAULT_FROEIGN_FIELD_NAME, modelClass);
//	}
//
//	/**
//	 * 关联查询
//	 * 
//	 * @param field
//	 *            关联的字段
//	 * @param modelClass
//	 *            关联的类
//	 * @return MyBatisModel对象
//	 */
//	public MyBatisModel foreignKey(String field, Class<? extends MyBatisModel> modelClass) {
//		if (field == null || StringUtils.isEmpty(field))
//			return this;
//
//		if (this.foreignKeys == null)
//			this.foreignKeys = new HashMap<String, MyBatisModel<?>>();
//		try {
//			// try {
//			// modelClass = (Class<? extends MyBatisModel>)
//			// Class.forName(modelClass.getName());
//			// } catch (ClassNotFoundException e) {
//			// e.printStackTrace();
//			// }
//			this.foreignKeys.put(field, modelClass.newInstance());
//		} catch (InstantiationException e) {
//			e.printStackTrace();
//		} catch (IllegalAccessException e) {
//			e.printStackTrace();
//		}
//		return this;
//	}
//
//	public int getId() {
//		return id;
//	}
//
//	public void setId(int id) {
//		this.id = id;
//	}
//
//	private void setPK(int pk) {
//		if (this.pk.equals(DEFAULT_PK_NAME)) {
//			this.setId(pk);
//		} else {
//			try {
//				BeanUtils.setProperty(this, this.pk, Integer.valueOf(pk));
//			} catch (IllegalAccessException e) {
//				e.printStackTrace();
//			} catch (InvocationTargetException e) {
//				e.printStackTrace();
//			}
//		}
//
//	}
//
//	private void setPKName(String pkname) {
//		this.pk = pkname;
//	}
//
//	public String getStartTime() {
//		return startTime;
//	}
//
//	public void setStartTime(String startTime) {
//		this.startTime = startTime;
//	}
//
//	public String getEndTime() {
//		return endTime;
//	}
//
//	public void setEndTime(String endTime) {
//		this.endTime = endTime;
//	}
//
//	public String getTableKey() {
//		return this.tableKey;
//	}
//
//	public int getTable() {
//		return table;
//	}
//
//	public void setTable(int table) {
//		this.table = table;
//	}
//
//	// 根据关键字段找对应表
//	private void setTableFromTableKey() {
//		if (this.getTableKey() == null)
//			return;
//		String key = null;
//		try {
//			key = BeanUtils.getProperty(this, this.getTableKey());
//		} catch (IllegalAccessException e) {
//			e.printStackTrace();
//		} catch (InvocationTargetException e) {
//			e.printStackTrace();
//		} catch (NoSuchMethodException e) {
//			e.printStackTrace();
//		}
//		if (key == null || key.trim().equals(""))
//			return;
//		this.setTable(Integer.valueOf(key) % tableNum);
//		// logger.debug("table key : " + this.getTable());
//	}
//
//	protected int getTableNum() {
//		return tableNum;
//	}
//
//	public String getToStringFun() {
//		return toStringFun;
//	}
//
//	public void setToStringFun(String toStringFun) {
//		this.toStringFun = toStringFun;
//	}
//
//	// @Override
//	// public String toString() {
//	// if (toStringFun != null)
//	// try {
//	// return (String) this.getClass().getMethod(toStringFun, null)
//	// .invoke(this, null);
//	// } catch (Exception e) {
//	// e.printStackTrace();
//	// }
//	// return null;
//	// }
}
